#pragma once
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <jsoncpp/json/json.h>

#define SEP " "
#define SEP_LEN strlen(SEP) // 不敢使用sizeof(),sizeof会算上/0
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP) // 不敢使用sizeof()

// "x op y" -> "content_len"\r\n"x op y"\r\n
// "exitcode result" -> "content_len"\r\n"exitcode result"\r\n

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

std::string enlength(const std::string &text)
{
    std::string send_string = std::to_string(text.size());
    send_string += LINE_SEP;
    send_string += text;
    send_string += LINE_SEP;
    return send_string;
}
// "content_len"\r\n"exitcode result"\r\n
bool delength(const std::string req_text, std::string *text)
{
    size_t pos = req_text.find(LINE_SEP);
    if (pos == std::string::npos)
        return false;
    int len = std::stoi(req_text.substr(0, pos));
    int text_pos = pos + LINE_SEP_LEN;
    *text = req_text.substr(text_pos, len);
    return true;
}

// 接受请求的构造
class Request
{
public:
    // 无参构造和有参构造
    Request()
    {
    }
    Request(int x, int y, char op)
        : _x(x), _y(y), _op(op)
    {
    }

    bool serialize(std::string *out)
    {
#ifdef MYSELF
        *out = "";
        //  结构化 -> "x op y";
        std::string x_string = std::to_string(_x);
        std::string y_string = std::to_string(_y);

        *out = x_string;
        *out += SEP;
        // 是可以直接加字符的
        *out += _op;
        *out += SEP;
        *out += y_string;
#else
        Json::Value root;
        root["first"] = _x;
        root["second"] = _y;
        root["oper"] = _op;
        Json::FastWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }

    // 输入数据"x op y"
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        size_t left = in.find(SEP);
        size_t right = in.rfind(SEP);
        if (left == std::string::npos || right == std::string::npos)
        {
            return false;
        }
        if (left == right)
        {
            return false;
        }
        // 这个是干啥的 懂了 “x y z" 这种
        if (right - (left + SEP_LEN) != 1)
        {
            return false;
        }
        std::string x_string = in.substr(0, left);
        std::string y_string = in.substr(right + SEP_LEN);

        if (x_string.empty())
        {
            return false;
        }

        if (y_string.empty())
        {
            return false;
        }
        _x = std::stoi(x_string);
        _y = std::stoi(y_string);
        _op = in[left + SEP_LEN];
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);
        _x = root["first"].asInt();
        _y = root["second"].asInt();
        // 这里的op 这样是没有问题的
        _op = root["oper"].asInt();

#endif
        return true;
    }

    ~Request()
    {
    }

public:
    // "x op y"
    int _x;
    int _y;
    char _op;
};

// 响应的构造
class Response
{
public:
    Response()
    {
    }
    Response(int exitcode, int result)
        : _exitcode(exitcode), _result(result)
    {
    }
    bool serialize(std::string *out)
    {
#ifdef MYSELF
        *out = "";
        std::string ec_string = std::to_string(_exitcode);
        std::string res_string = std::to_string(_result);

        *out = ec_string;
        *out += SEP;
        *out += res_string;
#else
        Json::Value root;
        root["exitcode"] = _exitcode;
        root["result"] = _result;

        Json::FastWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }

    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        // "exitcode result"
        auto mid = in.find(SEP);
        if (mid == std::string::npos)
            return false;
        std::string ec_string = in.substr(0, mid);
        std::string res_string = in.substr(mid + SEP_LEN);
        if (ec_string.empty() || res_string.empty())
            return false;

        _exitcode = std::stoi(ec_string);
        _result = std::stoi(res_string);
#else
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _exitcode = root["exitcode"].asInt();
        _result = root["result"].asInt();
#endif
        return true;
    }

    ~Response()
    {
    }

public:
    int _exitcode;
    int _result;
};
/**
 *
 * int sock 管道的操作符
 * inbuffer 一个输入型参数 ，为了处理发送过来的请求
 * req_text 为了截取除请求参数 如 "content_len"\r\n"x op y"\r\n" 发了很多个这样的请求 ，我们只截取出来一个
 */
bool recvPackage(int sock, std::string &inbuffer, std::string *req_text)
{
    char buffer[1024];
    while (true)
    {
        //  ssize_t recv(int sockfd, void *buf, size_t len, int flags);操作方式与read极为相似。就是多了一个参数，我怀疑是封装,返回值是读取了多少个字节
        size_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer;
            // 找到\r\n 注意返回的是迭代器
            size_t pos = inbuffer.find(LINE_SEP);
            if (pos == std::string::npos)
            {
                // 说明没找到这个字符串，就是还没有读到该位置
                continue;
            }
            // 往下面走说明是找到了这个分隔符，是第一个
            // string substr (size_t pos = 0, size_t len = npos) const;
            // "content_len"\r\n"x op y"\r\n"
            //  0           pos -> content_len
            std::string text_length_string = inbuffer.substr(0, pos);
            int text_len = std::stoi(text_length_string);
            int total_len = text_length_string.size() + text_len + 2 * LINE_SEP_LEN;

            if (inbuffer.size() < total_len)
            {
                std::cout << "你输入的消息，没有严格遵守我们的协议，正在等待后续的内容, continue" << std::endl;
                continue;
            }

            // 至少有一个完整的报文
            *req_text = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len);

            std::cout << "处理后#inbuffer:\n " << inbuffer << std::endl;

            break;
        }
        else
        {
            // 这里其实有两种情况
            // 1 是n == 0 并不是代表读取失败，而是另一端不进行输入了，且断开了连接
            // n<0 代表的是读取失败，但是我们这里对这两种情况都不进行处理
            break;
        }
    }
    return true;
}